from threading import Lock
import threading


# 负责监控破解状态，根据线程id存取破解状态
class CrackingStatusMonitor:
    def __init__(self):
        self.monitor_status = {}
        self.monitor_lock = {}

    def update_status(self, status):
        write_thread_id = self.__get_current_thread_id()
        if self.__is_status_existed(write_thread_id):
            self.monitor_lock[write_thread_id].acquire()
            self.monitor_status[write_thread_id].update(status)
            self.monitor_lock[write_thread_id].release()
            return

        self.monitor_lock[write_thread_id] = Lock()
        self.monitor_status[write_thread_id] = CrackingStatus(status)

    def __get_current_thread_id(self):
        return threading.current_thread().ident

    def __is_status_existed(self, thread_id):
        return self.monitor_status.get(thread_id)

    def get_status(self, write_thread_id):
        if self.__is_status_existed(write_thread_id):
            self.monitor_lock[write_thread_id].acquire()
            status = self.monitor_status[write_thread_id]
            self.monitor_lock[write_thread_id].release()
            return status

        return CrackingStatus({})


class CrackingStatus:
    def __init__(self, status):
        self.count = -1
        self.password = ''

        self.update(status)

    def update(self, status):
        self.count += 1
        self.password = status.get('password')
        if status.get('tip'):
            tip_printer.print('当前尝试的密码为：' + self.password)

    def get_count(self):
        return self.count

    def get_password(self):
        return self.password

    def __str__(self):
        return 'count={}, password={}'.format(self.count, self.password)


class TipPrinter:
    def __init__(self):
        self.last_tip = None

    def print(self, tip):
        self._print(tip)
        self.last_tip = tip

    def _print(self, tip):
        if self.last_tip:
            fresh = '  ' * len(self.last_tip)
            print('\r' + fresh, end='\r')
        print(tip, end='')


cracking_status_monitor = CrackingStatusMonitor()
tip_printer = TipPrinter()
